package com.mock.service.impl;

import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.registry.NacosServiceRegistry;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.mock.components.TomcatConfig;
import com.mock.service.ServiceRegistryService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

@Slf4j
@Service
public class NacosRegistryServiceImpl implements ServiceRegistryService {
    //注册服务表,重启后消失
    private final Map<String, Registration> mockNacosServiceManagerMap = new ConcurrentHashMap<>();
    //重启后消失
    private static final Map<String, List<Instance>> otherNacosServiceManagerMap = new ConcurrentHashMap<>();
    // 存储IP请求路径地址，key=各个mock服务的端口，value=真实的请求地址
    private static final Map<Integer, List<String>> MOCK_REAL_IPMAP = new ConcurrentHashMap<>();
    @Autowired
    private NacosDiscoveryProperties nacosDiscoveryProperties;
    @Autowired
    private NacosServiceRegistry serviceRegistry;
    @Autowired
    private NamingService namingService ;



    @Override
    public boolean register(String serviceId) {
        if (StringUtils.isBlank(serviceId)) {
            log.error("mock注册失败,serviceId为空");
            return false;
        }
        try {
            int port = TomcatConfig.getPort(serviceId);
            mockNacosServiceManagerMap.computeIfAbsent(serviceId, (serviceIdKey) -> {
                Registration docReg = new Registration() {
                    
                    @Override
                    public String getServiceId() {
                        return serviceIdKey;
                    }

                    @Override
                    public String getHost() {
                        return nacosDiscoveryProperties.getIp();
                    }
                    
                    @Override
                    public int getPort() {
                        return port;
                    }
                    
                    @Override
                    public boolean isSecure() {
                        return nacosDiscoveryProperties.isSecure();
                    }
                    
                    @Override
                    public URI getUri() {
                        return DefaultServiceInstance.getUri(this);
                    }
                    
                    @Override
                    public Map<String, String> getMetadata() {
                        Map<String, String> metadata = new ConcurrentHashMap<>();
                        metadata.put("server_type", "mock");
                        return metadata;
                    }
                };
                
              //  NamingService namingService = nacosServiceManager.getNamingService(this.nacosDiscoveryProperties.getNacosProperties());
                try {
                    // mock服务对应已注册的服务端口号作为key，用于拦截远程请求的能够映射到真实服务的ip
                    int key = docReg.getPort();

                    // 1、注册mock服务
                    List<Instance> allInstances = namingService.getAllInstances(serviceIdKey);
                    if (CollectionUtils.isNotEmpty(allInstances)) {
                        List<String> ips = new ArrayList<>(2);
                        for (Instance instance : allInstances) {
                            // 已存在的服务下线操作
                            instance.setEnabled(false);
                            namingService.registerInstance(serviceId, instance);
                            // 存放到缓存中key=mock的ip，value=下线的真实ip
                            ips.add(concatUrl(instance));
                            MOCK_REAL_IPMAP.put(key, ips);
                        }
                        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
                        otherNacosServiceManagerMap.put(serviceIdKey, allInstances);
                    } else {
                        /*
                        2、真实服务需要跟mock服务做映射，用于处理不需要mock的url进行转发操作。
                        由于mock服务重启之后，原真实服务状态为下线状态，ipMap也不存在，故重新
                        注册服务没有找到原服务时，需要重新获取存储起来。
                        map：key=mock的ip，value=下线的真实ip
                         */
                        List<Instance> instances = namingService.selectInstances(serviceIdKey, true);
                        if (CollectionUtils.isNotEmpty(instances)) {
                            List<String> urls = instances.stream()
                                    .filter(NacosRegistryServiceImpl::realServerfilter)
                                    .map(NacosRegistryServiceImpl::concatUrl)
                                    .collect(Collectors.toList());
                            MOCK_REAL_IPMAP.put(key, urls);
                        }
                    }
                } catch (NacosException e) {
                    log.error("NacosException", e);
                }
                
                serviceRegistry.register(docReg);
                return docReg;
            });
        } catch (Exception e) {
            log.error("mock注册失败,serviceId:{}", serviceId, e);
        }
        return true;
    }
    
    @Override
    public boolean deregister(String serviceId) {
        if (StringUtils.isBlank(serviceId)) {
            log.error("mock取消注册失败,serviceId为空");
            return false;
        }
        Registration docReg = mockNacosServiceManagerMap.get(serviceId);
        if (docReg == null) {
            log.warn("mock取消注册失败,没有注册过这个服务,serviceId:{}", serviceId);
            return false;
        }
        try {
         //   NamingService namingService = nacosServiceManager.getNamingService(this.nacosDiscoveryProperties.getNacosProperties());
            List<Instance> otherInstanceService = otherNacosServiceManagerMap.get(serviceId);
            try {
                
                if (CollectionUtils.isNotEmpty(otherInstanceService)) {
                    for (Instance instance : otherInstanceService) {
                        instance.setEnabled(true);
                        namingService.registerInstance(serviceId, instance);
                    }
                }
            } catch (NacosException e) {
                log.error("NacosException", e);
            }
            serviceRegistry.deregister(docReg);
            mockNacosServiceManagerMap.remove(serviceId);
        } catch (Exception e) {
            log.error("mock取消注册失败,serviceId:{}", serviceId, e);
        } finally {
            // 释放端口号
            TomcatConfig.releasePort(serviceId);
        }
        return true;
    }
    
    /**
     * 直接使用IP获取请求url
     *
     * @return
     */
    public static Map<Integer, List<String>> getMockRealIpmap() {
        return MOCK_REAL_IPMAP;
    }
    
    /**
     * 拼接url
     *
     * @param instance
     * @return
     */
    private static String concatUrl(Instance instance) {
        return instance.getIp() + ":" + instance.getPort();
    }
    
    /**
     * 过滤掉mock服务
     *
     * @param instance
     * @return
     */
    private static boolean  realServerfilter(Instance instance) {
        if (instance == null) {
            return false;
        }
        return StringUtils.isBlank(instance.getMetadata().get("server_type"));
    }








//    public void unregistAllMockEurekaInstance( InstanceInfo instanceInfo){
//        try {
//            MyDiscoveryClient myDiscoveryClient = new MyDiscoveryClient(instanceInfo,eurekaDiscoveryClient.getEurekaClientConfig());
//            log.info("Unregistering ...");
//            EurekaHttpResponse<Void> httpResponse = new DiscoveryClient.EurekaTransport().cancel(instanceInfo.getAppName(), instanceInfo.getId());
//            log.info( "deregister  status: " + httpResponse.getStatusCode());
//        } catch (Exception e) {
//            log.error("de-registration failed" + e.getMessage(), e);
//        }
//    }







    }

    

